/* port.c
###################################################################
#                       LINDO-API
#                    Sample Programs
#                  Copyright (c) 2001-2002
#
#         LINDO Systems, Inc.           312.988.7422
#         1415 North Dayton St.         info@lindo.com
#         Chicago, IL 60622             http://www.lindo.com
###################################################################
  File   : port.c
  Purpose: Solve a quadratic mixed integer programming problem.
  Model  : Portfolio Selection Problem with a Restriction on
           the Number of Assets

           MINIMIZE   0.5 w'Q w
           s.t.   sum_i  w(i)              =  1
                  sum_i  r(i)w(i)         >=  R
                  for_i  w(i) - u(i) x(i) <=  0   i=1...n
                  sum_i  x(i)             <=  K
                  for_i  x(i) are binary          i=1...n
           where
           r(i)  : return on asset i.
           u(i)  : an upper bound on the proportion of total budget
                   that could be invested on asset i.
           Q(i,j): covariance between the returns of i^th and j^th
                   assets.
           K     : max number of assets allowed in the portfolio
           w(i)  : proportion of total budget invested on asset i
           x(i)  : a 0-1 indicator if asset i is invested on.

  Data:
  Covariance Matrix:
               A1      A2      A3      A4      A5      A6      A7
       A1 [  1.00    0.11    0.04    0.02    0.08    0.03    0.10 ]
       A2 [  0.11    1.00    0.21    0.13    0.43    0.14    0.54 ]
       A3 [  0.04    0.21    1.00    0.05    0.16    0.05    0.20 ]
   Q = A4 [  0.02    0.13    0.05    1.00    0.10    0.03    0.12 ]
       A5 [  0.08    0.43    0.16    0.10    1.00    0.10    0.40 ]
       A6 [  0.03    0.14    0.05    0.03    0.10    1.00    0.12 ]
       A7 [  0.10    0.54    0.20    0.12    0.40    0.12    1.00 ]

  Returns Vector:
               A1      A2      A3      A4      A5      A6      A7
    r =   [  0.14    0.77    0.28    0.17    0.56    0.18    0.70 ]

  Maximum Proportion of Total Budget to be Invested on Assets
               A1      A2      A3      A4      A5      A6      A7
    u =   [  0.04    0.56    0.37    0.32    0.52    0.38    0.25 ]

  Target Return:
  R = 0.30

  Maximum Number of Assets:
  K = 3
*/
#include 
#include 
/* LINDO API header file */
#include "lindo.h"
/* license.h must be edited to include the license key
    that came with your software */
#include "license.h"
/* Define a macro to declare variables for
    error checking */
#define APIERRORSETUP  \
   int nErrorCode; \
   char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
/* Define a macro to do our error checking */
#define APIERRORCHECK  \
   if (nErrorCode) \
   { \
      if ( pEnv) \
      { \
         LSgetErrorMessage( pEnv, nErrorCode, \
          cErrorMessage); \
         printf("Errorcode=%d:  %s\n", nErrorCode, \
          cErrorMessage); \
      } else {\
         printf( "Fatal Error\n"); \
      } \
      exit(1); \
   } \
/* main entry point */
int main()
{
   APIERRORSETUP;
/* Number of constraints */
   int nM = 10;
/* Number of assets (7) plus number of indicator variables (7) */
   int nN = 14;
/* declare an instance of the LINDO environment object */
   pLSenv pEnv;
/* declare an instance of the LINDO model object */
   pLSmodel pModel;
  /****************************************************************
   * Step 1: Create a LINDO environment. MY_LICENSE_KEY in licence.h
   * must be defined using the key shipped with your software.
   ****************************************************************/
   pEnv = LScreateEnv ( &nErrorCode, MY_LICENSE_KEY);
   if ( nErrorCode == LSERR_NO_VALID_LICENSE)
   {
      printf( "Invalid License Key!\n");
      exit( 1);
   }
   APIERRORCHECK;
  /****************************************************************
   * Step 2: Create a model in the environment.
   ****************************************************************/
   pModel = LScreateModel ( pEnv, &nErrorCode);
   APIERRORCHECK;
   {
  /*****************************************************************
   * Step 3: Specify and load the LP portion of the model.
   *****************************************************************/
     /* The maximum number of assets allowed in a portfolio */
      int  K = 3;
     /* The target return */
      double R = 0.30;
     /* The direction of optimization */
      int objsense = LS_MIN;
      /* The objective's constant term */
      double objconst = 0.;
      /* There are no linear components in the objective function.*/
      double c[14] = { 0., 0., 0., 0., 0., 0.,0.,
                       0., 0., 0., 0., 0., 0.,0.};
      /* The right-hand sides of the constraints */
      double rhs[10] = { 1.0, R, 0., 0., 0., 0., 0., 0., 0., K};
      /* The constraint types */
      char contype[10] = {'E','G','L','L','L','L','L','L','L','L'};
      /* The number of nonzeros in the constraint matrix */
      int Anz = 35;
      /* The indices of the first nonzero in each column */
      int Abegcol[15] = { 0,  3,  6,  9, 12, 15, 18,
                         21, 23, 25, 27, 29, 31, 33,Anz};
      /* The length of each column. Since we aren't leaving
       * any blanks in our matrix, we can set this to NULL */
      int *Alencol = NULL;
      /* The nonzero coefficients */
      double A[35] = {  1.00, 0.14, 1.00,
                        1.00, 0.77, 1.00,
                        1.00, 0.28, 1.00,
                        1.00, 0.17, 1.00,
                        1.00, 0.56, 1.00,
                        1.00, 0.18, 1.00,
                        1.00, 0.70, 1.00,
                        -0.04, 1.00,
                        -0.56, 1.00,
                        -0.37, 1.00,
                        -0.32, 1.00,
                        -0.52, 1.00,
                        -0.38, 1.00,
                        -0.25, 1.00 };
      /* The row indices of the nonzero coefficients */
      int Arowndx[35] = { 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5,
                          0, 1, 6, 0, 1, 7, 0, 1, 8, 2, 9, 3,
                          9, 4, 9, 5, 9, 6, 9, 7, 9, 8, 9    };
      /* By default, all variables have a lower bound of zero
       * and an upper bound of infinity. Therefore pass NULL
       * pointers in order to use these default values. */
      double *lb = NULL, *ub = NULL;
  /*****************************************************************
   * Step 4: Specify and load the quadratic matrix
   *****************************************************************/
   /* The number of nonzeros in the quadratic matrix */
      int Qnz = 28;
   /* The nonzero coefficients in the Q-matrix */
   double Q[28] = { 1.00,  0.11,  0.04,  0.02,  0.08,  0.03,  0.10,
                    1.00,  0.21,  0.13,  0.43,  0.14,  0.54,
                    1.00,  0.05,  0.16,  0.05,  0.20,
                    1.00,  0.10,  0.03,  0.12,
                    1.00,  0.10,  0.40,
                    1.00,  0.12,
                    1.00 };
    /* The row indices of the nonzero coefficients in the Q-matrix*/
    int  Qrowndx[28] = { -1, -1, -1, -1, -1, -1, -1,
                         -1, -1, -1, -1, -1, -1,
                         -1, -1, -1, -1, -1,
                         -1, -1, -1, -1,
                         -1, -1, -1,
                         -1, -1,
                         -1 };
    /* The indices of the first nonzero in each column in the Q-matrix */
    int Qcolndx1[28] = {  0, 1, 2, 3, 4, 5, 6,
                          1, 2, 3, 4, 5, 6,
                          2, 3, 4, 5, 6,
                          3, 4, 5, 6,
                          4, 5, 6,
                          5, 6,
                          6};
    int Qcolndx2[28] = {  0, 0, 0, 0, 0, 0, 0,
                          1, 1, 1, 1, 1, 1,
                          2, 2, 2, 2, 2,
                          3, 3, 3, 3,
                          4, 4, 4,
                          5, 5,
                          6};
    /* Pass the linear portion of the data to problem structure
     * by a call to LSloadLPData() */
     nErrorCode = LSloadLPData( pModel, nM, nN, objsense, objconst,
                                c, rhs, contype,
                                Anz, Abegcol, Alencol, A, Arowndx,
                                lb, ub);
     APIERRORCHECK;
    /* Pass the quadratic portion of the data to problem structure
     * by a call to LSloadQCData()  */
     nErrorCode = LSloadQCData(pModel, Qnz, Qrowndx,
                               Qcolndx1, Qcolndx2, Q);
     APIERRORCHECK;
    /* Pass the integrality restriction to problem structure
     * by a call to LSloadVarData()  */
     {
       char vartype[14] ={ 'C','C','C','C','C','C','C',   /* w(j) */
                           'B','B','B','B','B','B','B' }; /* x(j) */
       nErrorCode = LSloadVarType(pModel, vartype);
       APIERRORCHECK;
     }
   }
  /*****************************************************************
   * Step 5: Perform the optimization using the MIP solver
   *****************************************************************/
   nErrorCode = LSsolveMIP( pModel, NULL);
   APIERRORCHECK;
   {
  /*****************************************************************
   * Step 6: Retrieve the solution
   *****************************************************************/
      int i;
      double x[14], MipObj;
      /* Get the value of the objective and solution */
      nErrorCode = LSgetInfo(pModel, LS_DINFO_MIP_OBJ, &MipObj);
      APIERRORCHECK;

      LSgetMIPPrimalSolution( pModel, x) ;
      APIERRORCHECK;
      printf ("*** Optimal Portfolio Objective = %f\n", MipObj);
      for (i = 0; i < nN/2; i++)
        printf( "Invest %5.2f percent of total budget in asset %d.\n",
                 100*x[i],i+1 );
      printf ("\n");
   }
  /*****************************************************************
   * Step 7: Delete the LINDO environment
   *****************************************************************/
   nErrorCode = LSdeleteEnv( &pEnv);
 /* Wait until user presses the Enter key */
   printf("Press  ...");
   getchar();
}